/*
 * Created on 7-Nov-2004
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package org.mtdownload.download;

import java.io.Serializable;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.List;
import java.util.ArrayList;


/**
 * A download task that is shown in the tasks list
 * @author sergiu
 */
public class DownloadTask implements Serializable{

	/**
	 * Comment for <code>serialVersionUID</code>
	 */
	private static final long serialVersionUID = 3258130267196569398L;
	
	public static final String[] columnNames=new String[]{"!","File","Status","Percent","Speed","Completed/Total","ETA","Elapsed","Threads","URL"};
	public final static int START_NOW=1;
	public final static int START_MANUALLY=2;
	public final static int START_SCHEDULED=3;
	
	public final static int SPEED_BYTES=1;
	public final static int SPEED_KILOBYTES=2;
	public final static int SPEED_MEGABYTES=3;
	
	private String destinationFileName="";
	private String destinationDirectory="";
	private List<String> alternateURLs=new ArrayList<String>();
	private String url="";
	private double percentComplete=0;
	private long speed=0; //in bytes.
	private int threadNum=1;
	private boolean complete=false;
	private int startTime=START_NOW;
	private long id=-1;
	private boolean isStarted=false;
	private long fileLength=0;
	private long completedBytes=0;
	private String status="";
	private String referer;
	private long eta; //in seconds
	private long elapsed=0;//in seconds
	private int index=0;//the index of this download (starts from 0 and is in the order that the downloads are added)
	private DownloadMasterThread masterThread=null;
	private String username=null;
	private String password=null;
	private static NumberFormat nFormat=NumberFormat.getNumberInstance();
	private long[] threadsSpeed=null;
	private boolean allThreadsSpawned=false;
	
	public DownloadTask(){
		setID(System.currentTimeMillis());
	}
	
	/**
	 * @return Returns the alternateURLs.
	 */
	public List getAlternateURLs() {
		return alternateURLs;
	}
	/**
	 * @param alternateURLs The alternateURLs to set.
	 */
	public void setAlternateURLs(List<String> alternateURLs) {
		this.alternateURLs = alternateURLs;
	}

	public void addAlternateURL(String alternateURL) {
		alternateURLs.add(alternateURL);
	}
	public void removeAlternateURL(String alternateURL) {
		alternateURLs.remove(alternateURL);
	}	
	
	/**
	 * @return Returns the complete.
	 */
	public boolean isComplete() {
		return complete;
	}
	/**
	 * @param complete The complete to set.
	 */
	public void setComplete(boolean complete) {
		this.complete = complete;
	}
	/**
	 * @return Returns the destinationFileName.
	 */
	public String getDestinationFileName() {
		return destinationFileName;
	}
	/**
	 * @param destinationFileName The destinationFileName to set.
	 */
	public void setDestinationFileName(String destinationFileName) {
		this.destinationFileName = destinationFileName;
	}
	/**
	 * @return Returns the percentComplete.
	 */
	public double getPercentComplete() {
		return percentComplete;
	}	
	/**
	 * @param percentComplete The percentComplete to set.
	 */
	public void setPercentComplete(double percentComplete) {
		this.percentComplete = percentComplete;
	}
	
	/**
	 * @return Returns the speed.
	 */
	public long getSpeed() {
		return speed;
	}
	/**
	 * @param speed The speed to set.
	 */
	public void setSpeed(long speed) {
		this.speed = speed;
	}
	/**
	 * @return Returns the threadNum.
	 */
	public int getThreadNum() {
		return threadNum;
	}
	/**
	 * @param threadNum The threadNum to set.
	 */
	public void setThreadNum(int threadNum) {
		this.threadNum = threadNum;
	}
	/**
	 * @return Returns the url.
	 */
	public String getUrl() {
		return url;
	}
	/**
	 * @param url The url to set.
	 */
	public void setUrl(String url) {
		this.url = url;
	}
	/**
	 * @return Returns the startTime.
	 */
	public int getStartTime() {
		return startTime;
	}
	/**
	 * @param startTime The startTime to set.
	 */
	public void setStartTime(int startTime) {
		if(startTime>=START_NOW && startTime<=START_SCHEDULED){
			this.startTime = startTime;
		}
	}
	
	private synchronized void setID(long id){
		this.id=id;
	}
	
	private long getId(){
		return id;
	}
	
	public boolean equals(Object obj){
		if(obj==null) return false;
		if(!(obj instanceof DownloadTask)) return false;
		DownloadTask t=(DownloadTask)obj;
		return getId()==t.getId();
	}
	/**
	 * @return Returns the isStarted.
	 */
	public boolean isStarted() {
		return isStarted;
	}
	/**
	 * @param isStarted The isStarted to set.
	 */
	public void setStarted(boolean isStarted) {
		this.isStarted = isStarted;
	}
	
	public static String getHumanFriendlySpeed(int type,long speed){
		String result="";
		switch(type){
			case SPEED_BYTES:
				return String.valueOf(speed);
			case SPEED_KILOBYTES:
				double kilo=speed/1024.0;				
				nFormat.setMaximumFractionDigits(0);
				return nFormat.format(kilo);
			case SPEED_MEGABYTES:
				double mega=speed/(1024.0*1024.0);
				nFormat.setMaximumFractionDigits(2);
				return nFormat.format(mega);				
			default:
				return "";
		}		
	}
	
	public String getHumanFriendlySpeed(int type){
		return getHumanFriendlySpeed(type,getSpeed());
	}
	
	/**
	 * Used to return ETA.
	 * @param time the number of seconds
	 * @return
	 */
	public String getHumanFriendlyTime(long time){
		long maxTimeAccepted=3600*24*30;//30 days
		if(time>maxTimeAccepted){						
			DecimalFormatSymbols symbols=new DecimalFormatSymbols();
			return symbols.getInfinity() ;
		}
		if(time<0){
			return "Unknown";
		}		
		int hours;
		int mins;
		int secs;
		if(time>3600){//we have to wait more than an hour
			hours=(int)(time/3600);
			time=time-(hours*3600);
			mins=(int)(time/60);
			time=time-(mins*60);
			secs=(int)time;
			return hours+":"+((mins>9)?""+mins:("0"+mins))+":"+((secs>9)?""+secs:"0"+secs);
		}
		if(time>60){
			mins=(int)(time/60);
			time=time-(mins*60);
			secs=(int)time;
			return ((mins>9)?""+mins:("0"+mins))+":"+((secs>9)?""+secs:"0"+secs);
		}
		return "00:"+((time>9)?""+time:"0"+time);
	}
	
	public String getHumanFriendlyBytes(long bytes){
		NumberFormat format=NumberFormat.getInstance();
		double kilo=1024;
		double mega=1024*kilo;
		double giga=1024*mega;
		format.setMaximumFractionDigits(2);
		if(bytes<kilo){			
			return format.format(bytes);
		}
		if(bytes<=mega){
			double kiloBytes=(double)bytes/kilo;
			return format.format(kiloBytes)+"KB";
		}
		if(bytes<=giga){
			double n=(double)bytes/mega;
			return format.format(n)+"MB";
		}
		if(bytes>giga){
			double n=(double)bytes/giga;
			return format.format(n)+"GB";			
		}
		return "";
	}
	
	public String getHumanFriendlyPercent(){		
		NumberFormat nFormat=NumberFormat.getPercentInstance();
		return nFormat.format(getPercentComplete());
	}
	/**
	 * @return Returns the fileLength.
	 */
	public long getFileLength() {
		return fileLength;
	}
	/**
	 * @param fileLength The fileLength to set.
	 */
	public void setFileLength(long fileLength) {
		this.fileLength = fileLength;
	}
	/**
	 * @return Returns the status.
	 */
	public String getStatus() {
		return status;
	}
	/**
	 * @param status The status to set.
	 */
	public void setStatus(String status) {
		this.status = status;
	}
	/**
	 * @return Returns the referer.
	 */
	public String getReferer() {
		return referer;
	}
	/**
	 * @param referer The referer to set.
	 */
	public void setReferer(String referer) {
		this.referer = referer;
	}
	/**
	 * @return Returns the completedBytes.
	 */
	public long getCompletedBytes() {
		return completedBytes;
	}
	/**
	 * @param completedBytes The completedBytes to set.
	 */
	public void setCompletedBytes(long completedBytes) {
		this.completedBytes = completedBytes;
	}
	/**
	 * @return Returns the eta.
	 */
	public long getEta() {
		return eta;
	}
	/**
	 * @param eta The eta to set.
	 */
	public void setEta(long eta) {
		this.eta = eta;
	}
	
	public String toString(){
		return getDestinationFileName();
	}
	/**
	 * @return Returns the index.
	 */
	public int getIndex() {
		return index;
	}
	/**
	 * @param index The index to set.
	 */
	public void setIndex(int index) {
		this.index = index;
	}
	/**
	 * @return Returns the masterThread.
	 */
	public DownloadMasterThread getMasterThread() {
		return masterThread;
	}
	/**
	 * @param masterThread The masterThread to set.
	 */
	public void setMasterThread(DownloadMasterThread masterThread) {
		this.masterThread = masterThread;
	}
	
	public void stopDownload(){	
		if(!isComplete()){
			setStatus("Paused");
		}
		setStarted(false);
		masterThread.setCancelled(true);
		if(masterThread.getThreads()!=null){
			for(DownloadThread thread:masterThread.getThreads()){
				thread.setCancelled(true);
			}
		}
	}
	
	public void resumeDownload(){		
		setStarted(true);
		masterThread.setCancelled(false);
		if(masterThread.getThreads()!=null){
			for(DownloadThread thread:masterThread.getThreads()){
				thread.setCancelled(false);
			}
		}
	}
	
	/**
	 * @return Returns the password.
	 */
	public String getPassword() {
		return password;
	}
	/**
	 * @param password The password to set.
	 */
	public void setPassword(String password) {
		this.password = password;
	}
	/**
	 * @return Returns the username.
	 */
	public String getUsername() {
		return username;
	}
	/**
	 * @param username The username to set.
	 */
	public void setUsername(String username) {
		this.username = username;
	}
	/**
	 * @return Returns the elapsed.
	 */
	public long getElapsed() {
		return elapsed;
	}
	/**
	 * @param elapsed The elapsed to set.
	 */
	public void setElapsed(long elapsed) {
		this.elapsed = elapsed;
	}

	/**
	 * @return Returns the threadsSpeed.
	 */
	public long[] getThreadsSpeed() {
		if(threadsSpeed!=null){
			//System.out.println(threadsSpeed[0]);
			//System.out.println(threadsSpeed[1]);
			//System.out.println(threadsSpeed[2]);
		}
		return threadsSpeed;
	}
	/**
	 * @param threadsSpeed The threadsSpeed to set.
	 */
	public void setThreadsSpeed(long[] threadsSpeed) {
		this.threadsSpeed = threadsSpeed;
	}
	
	public long getSpeedForThread(int threadIndex){
		if(threadsSpeed==null || threadsSpeed.length>=threadIndex){
			return -1;
		}
		return threadsSpeed[index]; 
	}
	
	public void setSpeedForThread(int threadIndex,long s){
//		System.out.println("ss="+s);
//		System.out.println("threadIndex="+threadIndex);
//		System.out.println("threadsSpeed.length="+threadsSpeed.length);
		if(threadsSpeed==null || threadsSpeed.length<=threadIndex){
			return;
		}
		//System.out.println("ss="+s);
		threadsSpeed[threadIndex]=s;
//		System.out.println("threadsSpeed[index]="+threadsSpeed[index]);
	}

	/**
	 * @return Returns the destinationDirectory.
	 */
	public String getDestinationDirectory() {
		return destinationDirectory;
	}

	/**
	 * @param destinationDirectory The destinationDirectory to set.
	 */
	public void setDestinationDirectory(String destinationDirectory) {
		this.destinationDirectory = destinationDirectory;
	}

	/**
	 * @return Returns the allThreadsSpawned.
	 */
	public boolean isAllThreadsSpawned() {
		return allThreadsSpawned;
	}

	/**
	 * @param allThreadsSpawned The allThreadsSpawned to set.
	 */
	public void setAllThreadsSpawned(boolean allThreadsSpawned) {
		this.allThreadsSpawned = allThreadsSpawned;
	}
	
}
